package com.ncr.teradata.bireport;

import java.math.BigDecimal;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Report.java
 * 报表类
 * 根据用户的各种报表属性和条件设置，对缓存中的报表数据进行筛选过滤、纵向选择、动态聚合、
 * 计算派生度量、行列互换重组数据集、汇总小计
 * 最后返回满足条件并符合展现格式的报表数据
 * 最终返回的数据行格式如下：
 * Row{维度1,...,维度n,[小计1,...,小计n],度量1,...,度量n,派生度量1,...派生度量n,[度量1,...,度量n,派生度量1,...派生度量n],小计1,...小计n}
 *
 * @author ylpeng
 * @date Mar 12, 2007
 */
public class Report
{
	//报表数据集
	private ReportData reportData;
	
	//报表的筛选条件
	//格式1{["filtVal1"|"filtMethod"],"filtVal2",...,"filtValn"}
	//filtVal1到filtValn为筛选的条件限定值，filtMethod为筛选方法
	private Map filters;
	
	//报表显示的维度
	private List dimensions;		//所有维度
	private List rowDimensions;	//行维度
	private List colDimensions;	//列维度
	
	//报表显示的度量
	private List measures;
	
	//报表计算出来的派生度量，每个派生度量以String[]对象存储
	//格式：{"dmName","dmType","operand1","...","operandn"}
	//dmName为派生度量名称；dmType为派生度量的类型；
	//operand1到operandn为计算这个派生度量需要涉及到的操作数，即参加计算的度量
	private List deriveMeasures;
	
	//报表显示时隐藏的度量，通常这些度量只是用来参与派生度量的计算
	private List hiddenMeasures;
	
	//报表小计
	//格式：{"position","calcType","measure"}
	//position为小计位置，calcType为小计计算方法，measure为度量名称
	private List subtotals;
	
	//数据可见范围（用于报表数据权限的控制）
	private String cityScope = null;		//市级范围
	private String countryScope = null;	//县级范围
	
	//默认显示的地域维度别名（用于控制报表在地域维度上显示的维度层次）
	private String defaultAreaIdAlias = null;		//地域ID列别名
	private String defaultAreaNameAlias = null;	//地域NAME列别名
	
	//常量配置
	public static final String CYCLE_RATIO = "1";				//环比或同比
	public static final String COMPOSING_RATIO = "2";			//占比
	public static final String RANKING = "3";					//排名
	public static final String RATIO = "4";						//比、比率、比例
	public static final String BRING_INCREASE_RATIO = "5";		//拉动增长率
	public static final String INVERSE_RATIO = "6";				//反比
	public static final String DIVIDE = "7";					//除法计算
	public static final String DISCOUNT_RATIO = "8";			//折扣率
	public static final String ROW_DIMENSION = "X";		//行维度标识
	public static final String COLUMN_DIMENSION = "Y";	//列维度标识
	public static final String SUM = "SUM";		//小计计算方法为“求和”
	public static final String AVG = "AVG";		//小计计算方法为“求平均值”
	public static final String TOP = "TOP";			//小计位置为“顶部”
	public static final String BOTTOM = "BOTTOM";	//小计位置为“底部”
	public static final String LEFT = "LEFT";		//小计位置为“左边”
	public static final String RIGHT = "RIGHT";		//小计位置为“右边”
	public static final String BETWEEN = "BETWEEN";								//筛选在...之间
	public static final String GREATER_THAN_OR_EQUAL = "GREATER_THAN_OR_EQUAL";	//筛选大于等于
	public static final String LESS_THAN_OR_EQUAL = "LESS_THAN_OR_EQUAL";		//筛选小于等于
	
	/**
	 * 构造函数
	 *
	 *@param reportName String 报表名称
	 */
	public Report(String reportName) {
		//reportData = ReportCache.getCachedReportData(reportName);
		ReportServer rServer = ReportServer.getInstance();
		if(null==reportData)
		   reportData = rServer.getReportData(reportName);
		
		filters = new HashMap();
		dimensions = new ArrayList();
		rowDimensions = new ArrayList();
		colDimensions = new ArrayList();
		measures = new ArrayList();
		deriveMeasures = new ArrayList();
		hiddenMeasures = new ArrayList();
		subtotals = new ArrayList();
		
		cityScope = InitParam.PROVINCECODE_IN_CITYCODE;
		countryScope = InitParam.CITYCODE_IN_COUNTRYCODE;
		defaultAreaIdAlias = InitParam.DIMENSION_ALIAS_INSQL_CITY;
		defaultAreaNameAlias = InitParam.DIMENSION_ALIAS_INSQL_CITY_NAME;
	}
	
	/**
	 * 构造函数
	 * 根据当前登陆的用户进行报表数据权限的控制
	 *
	 *@param reportName String 报表名称
	 *@param staff 当前登陆的用户
	 */
	public Report(String reportName,String p_cityCd,String p_countryCd) {
		this(reportName);
		
		//通过用户实体传递参数 StaffSessBean staff
		//cityScope = staff.getCityScope();
		//countryScope = staff.getCountryScope();
		cityScope = p_cityCd;
		countryScope = p_countryCd;
		
		if (!cityScope.equals(InitParam.PROVINCECODE_IN_CITYCODE)){
			addFilter(InitParam.DIMENSION_ALIAS_INSQL_CITY,new String[]{cityScope});
			int idColIdx = reportData.getColumnIndex(InitParam.DIMENSION_ALIAS_INSQL_COUNTRY);
			int nameColIdx = reportData.getColumnIndex(InitParam.DIMENSION_ALIAS_INSQL_COUNTRY_NAME);
			if (idColIdx != -1 && nameColIdx != -1){
				defaultAreaIdAlias = InitParam.DIMENSION_ALIAS_INSQL_COUNTRY;
				defaultAreaNameAlias = InitParam.DIMENSION_ALIAS_INSQL_COUNTRY_NAME;
			}
		}
		if (!countryScope.equals(InitParam.CITYCODE_IN_COUNTRYCODE)){
			addFilter(InitParam.DIMENSION_ALIAS_INSQL_COUNTRY,new String[]{countryScope});
		}
	}
	
	/**
	 * 构造报表展示需要的数据，整个过程需要六个步骤完成（顺序不能打乱）
	 * 1、根据用户的筛选设置，对缓存中的数据进行横向过滤
	 * 2、根据用户选择的维度和度量，对缓存中的数据进行纵向选择
	 * 3、对数据集进行动态聚合
	 * 4、计算报表派生度量（环比、同比、占比、排名等）
	 * 5、如果有列维度，则按要求将数据集行列互换，重新组织数据
	 * 6、根据用户的小计要求计算报表小计数据
	 *
	 *@return List 返回报表展示需要的数据列表
	 */
	public List buildData(){
		List datas = new ArrayList();
		doFilter(datas);
		doSelect(datas);
		doAggregate(datas);
		doCalculateDM(datas);
		doXYSwap(datas);
		doSubtotal(datas);
		return datas;
	}
	
	/**
	 * 构造报表数据，并以字符串的形式返回报表数据的表格展示内容
	 * 报表格式目前只支持最多两个行维度和最多一个列维度
	 * 
	 * @return string 返回报表数据的表格展示内容
	 */
	public String buildTableData(){
		StringBuffer sb = new StringBuffer(); 
		List datas = buildData();
		
		sb.append("<table border='1' width='100%' class='tablestyle1' style='table-layout:fixed' cellspacing='0' cellpadding='0' bordercolordark='#ccffff' bordercolorlight='#9999cc'>");
		String curRowDimValue = "!@#$";
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			if (i == 0){
				for (int j = 0; j < colDimensions.size(); j++){
					sb.append("<tr align='center'>");
					String dimName = (String)colDimensions.get(j);
					Object[] dimValues = getDimensionValues(dimName);
					if (rowDimensions.size() > 0){
						int colIdx = reportData.getColumnIndex(dimName);
						sb.append("<td colspan='" + rowDimensions.size() + "'>" + reportData.getColumnLabel(colIdx + 1) + "</td>");
					}
					for (int k = 0; k < dimValues.length; k++)
						sb.append("<td colspan='" + (measures.size() - hiddenMeasures.size()) + "'>" + (String)dimValues[k] + "</td>");
					if (subtotals.size() > 0){
						for (int m = 0; m < subtotals.size(); m++){
							String[] subtotal = (String[])subtotals.get(m);
							if (subtotal[0].equals(RIGHT)){
								sb.append("<td align='center'>小计</td>");
								break;
							}
						}
					}
					sb.append("</tr>");
				}
				sb.append("<tr align='center'>");
				for (int j = 0; j < row.length; j++){
					String colName = "";
					if (j < rowDimensions.size())
						colName = (String)rowDimensions.get(j);
					else
						colName = (String)measures.get((j - rowDimensions.size()) % measures.size());
					if (isHiddenMeasure(colName))
						continue;
					int colIdx = reportData.getColumnIndex(colName);
					if (colIdx == -1)
						sb.append("<td>" + colName + "</td>");
					else
						sb.append("<td>" + reportData.getColumnLabel(colIdx + 1) + "</td>");
				}
				sb.append("</tr>");
			}
			
			sb.append("<tr align='right'>");
			for (int j = 0; j < row.length; j++){
				if (j < rowDimensions.size()){
					boolean isEnd = false;
					if (i == datas.size() - 1 && subtotals.size() > 0){
						for (int m = 0; m < subtotals.size(); m++){
							String[] subtotal = (String[])subtotals.get(m);
							if (subtotal[0].equals(BOTTOM)){
								sb.append("<td align='center'>小计</td>");
								isEnd = true;
								break;
							}
						}
					}
					if (!isEnd){
						if (!((String)row[j]).equals(curRowDimValue)){
							if (j < rowDimensions.size() - 1){
								curRowDimValue = (String)row[j];
								int rowSpanNbr = 0;
								for (int k = i; k < datas.size(); k++){
									Object[] tempRow = (Object[])datas.get(k);
									if (((String)tempRow[j]).equals(curRowDimValue))
										rowSpanNbr++;
									else
										break;
								}
								sb.append("<td align='center' bgcolor='e8f4ff' rowspan='" + rowSpanNbr + "'>" + row[j] + "</td>");
							}
							else
								sb.append("<td align='center'>" + row[j] + "</td>");
						}
					}
				}
				else{
					String meaName = (String)measures.get((j - rowDimensions.size()) % measures.size());
					if (isHiddenMeasure(meaName))
						continue;
					String postFix = "";
					if (deriveMeasures.size() > 0){
						//String meaName = (String)measures.get((j - rowDimensions.size()) % measures.size());
						for (int k = 0; k < deriveMeasures.size(); k++){
							String[] dMeasure = (String[])deriveMeasures.get(k);
							if (dMeasure[0].equals(meaName)){
								if (dMeasure[1].equals(CYCLE_RATIO) || dMeasure[1].equals(COMPOSING_RATIO) || dMeasure[1].equals(RATIO) 
										 || dMeasure[1].equals(BRING_INCREASE_RATIO) || dMeasure[1].equals(INVERSE_RATIO) || dMeasure[1].equals(DISCOUNT_RATIO))
									postFix = "%";
								break;
							}
						}
					}
					sb.append("<td>" + row[j] + postFix + "</td>");
				}
			}
			sb.append("</tr>");
		}
		sb.append("</table>");
		
		return sb.toString();
	}
	
	/**
	 * 过滤数据集
	 *
	 *@param datas List 将符合条件的数据存入该List对象中
	 */
	private void doFilter(List datas){
		List allData = reportData.getData();
		
		if (filters.size() == 0){
			for (int i = 0; i < allData.size(); i++)
				datas.add(allData.get(i));
			return;
		}
		
		for (int i = 0; i < allData.size(); i++){
			Object[] row = (Object[])allData.get(i);
			int count = 0;
			Iterator iterator = filters.keySet().iterator();
			while (iterator.hasNext()){
				String fName = (String)iterator.next();
				String[] fValues = (String[])filters.get(fName);
				int idx = reportData.getColumnIndex(fName);
				String colValue = (String)row[idx];
				if (fValues[0].equalsIgnoreCase(BETWEEN)){
					Collator comparator = Collator.getInstance();
					if (comparator.compare(colValue,fValues[1]) >= 0 && comparator.compare(colValue,fValues[2]) <= 0)
						count++;
				}
				else if (fValues[0].equalsIgnoreCase(GREATER_THAN_OR_EQUAL)){
					Collator comparator = Collator.getInstance();
					if (comparator.compare(colValue,fValues[1]) >= 0)
						count++;
				}
				else if (fValues[0].equalsIgnoreCase(LESS_THAN_OR_EQUAL)){
					Collator comparator = Collator.getInstance();
					if (comparator.compare(colValue,fValues[1]) <= 0)
						count++;
				}
				else{
					//如不指定筛选方法则默认为相等性匹配
					for (int j = 0; j < fValues.length; j++){
						if(colValue.equals(fValues[j])){
							count++;
							break;
						}
					}
				}
			}
			if(count == filters.size())
				datas.add(row);
		}
	}
	
	/**
	 * 对数据集纵向选择
	 *
	 *@param datas List 将符合条件的数据存入该List对象中
	 */
	private void doSelect(List datas){
		if (dimensions.size() == 0 && measures.size() == 0){
			datas.clear();
			return;
		}
		if (dimensions.size() + measures.size() == reportData.getColumnCount())
			return;
		
		int[] colIdx = new int[dimensions.size() + measures.size()];
		for (int i = 0; i < dimensions.size(); i++){
			colIdx[i] = reportData.getColumnIndex((String)dimensions.get(i));
		}
		for (int i = dimensions.size(); i < colIdx.length; i++){
			colIdx[i] = reportData.getColumnIndex((String)measures.get(i - dimensions.size()));
		}
		
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			Object[] tempRow = new Object[colIdx.length];
			for (int j = 0; j < colIdx.length; j++){
				tempRow[j] = row[colIdx[j]];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 对数据集进行动态聚合
	 *
	 *@param datas List 将聚合后的数据存入该List对象中
	 */
	private void doAggregate(List datas){
		if (dimensions.size() == 0 && measures.size() == 0)
			return;
		if (dimensions.size() + measures.size() == reportData.getColumnCount())
			return;
		
		Map dimIdxMapping = new HashMap();
		List tempData = new ArrayList();
		int index = -1;
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			String dimStr = "";
			for (int j = 0; j < dimensions.size(); j++){
				dimStr += (String)row[j];
			}
			
			if(dimIdxMapping.containsKey(dimStr)){
				int idx = ((Integer)dimIdxMapping.get(dimStr)).intValue();
				Object[] oldRow = (Object[])tempData.get(idx);
				for (int j = dimensions.size(); j < oldRow.length; j++){
					oldRow[j] = ((BigDecimal)oldRow[j]).add((BigDecimal)row[j]);
				}
			}
			else{
				index++;
				dimIdxMapping.put(dimStr,new Integer(index));
				tempData.add(row);
			}
		}
		
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算报表派生度量
	 *
	 *@param datas List 将计算后的数据存入该List对象中
	 */
	private void doCalculateDM(List datas){
		if (deriveMeasures.size() == 0 || measures.size() == 0)
			return;
		
		for (int i = 0; i < deriveMeasures.size(); i++){
			int dmAddIdx = -1;
			String[] dMeasure = (String[])deriveMeasures.get(i);
			int operand1Idx = -1;
			int operand2Idx = -1;
			int existMea = 0;
			for (int j = 2; j < dMeasure.length; j++){
				boolean exist = false;
				for (int k = 0; k < measures.size(); k++){
					if (dMeasure[j].equals((String)measures.get(k))){
						exist = true;
						existMea++;
						dmAddIdx = k + 1 > dmAddIdx ? k + 1 : dmAddIdx;
						if (existMea == 1)
							operand1Idx = dimensions.size() + k;
						if (existMea == 2)
							operand2Idx = dimensions.size() + k;
						break;
					}
				}
				if (!exist)
					break;
			}
			if (existMea + 2 < dMeasure.length){
				deriveMeasures.remove(i);
				i--;
				continue;
			}
			
			if (dMeasure[1].equals(Report.CYCLE_RATIO))
				calculateCycleRatio(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.COMPOSING_RATIO))
				calculateComposingRatio(datas,operand1Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(RANKING))
				calculateRanking(datas,operand1Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.RATIO))
				calculateRatio(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.BRING_INCREASE_RATIO))
				calculateBringIncreaseRatio(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.INVERSE_RATIO))
				calculateInverseRatio(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.DIVIDE))
				calculateDivide(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else if (dMeasure[1].equals(Report.DISCOUNT_RATIO))
				calculateDiscountRatio(datas,operand1Idx,operand2Idx,dmAddIdx + dimensions.size());
			else 
				;
			measures.add(dmAddIdx,dMeasure[0]);
		}
	}
	
	/**
	 * 计算环比、同比
	 * 计算公式：1、(operand1 - operand2) / operand2 * 100
	 *          2、(operand1 / operand2 - 1) * 100
	 * 这里按第一种公式计算
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateCycleRatio(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.subtract(operand2).divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==operand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算占比
	 * 计算公式：operand1 / SUM(operand1) * 100
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateComposingRatio(List datas,int operand1Idx,int dmAddIdx){
		BigDecimal operand2 = new BigDecimal(0);
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			operand2 = operand2.add((BigDecimal)row[operand1Idx]);
		}
		if(operand2.doubleValue() == 0)
			operand2 = new BigDecimal(1);
		
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal result = operand1.divide(operand2,4,5).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==operand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算排名
	 * 计算方法：对operand1的排序，然后再确定排名
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateRanking(List datas,int operand1Idx,int dmAddIdx){
		BigDecimal[] tmpOperand = new BigDecimal[datas.size()];
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			tmpOperand[i] = (BigDecimal)row[operand1Idx];
		}
		Arrays.sort(tmpOperand);
		
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal result = null;
			int sortNo = 0;
			for (int j = tmpOperand.length - 1; j >=0; j--){
				sortNo++;
				if (tmpOperand[j] == (BigDecimal)row[operand1Idx]){
					result = new BigDecimal(sortNo);
					break;
				}
			}
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算比、比率、比例
	 * 计算公式：operand1 / operand2 * 100
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateRatio(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==operand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算拉动增长率
	 * 计算公式：(operand1 - operand2) / SUM(operand2) * 100
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateBringIncreaseRatio(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		BigDecimal sumOperand2 = new BigDecimal(0);
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			sumOperand2 = sumOperand2.add((BigDecimal)row[operand2Idx]);
		}
		if(sumOperand2.doubleValue() == 0)
			sumOperand2 = new BigDecimal(1);
		
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal result = operand1.subtract(operand2).divide(sumOperand2,4,5).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==sumOperand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算反比
	 * 计算公式：(1 - operand1 / operand2) * 100
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateInverseRatio(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = (new BigDecimal(1)).subtract(operand1.divide(divideOperand,4,5)).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==operand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 除法计算
	 * 计算公式：operand1 / operand2
	 *
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateDivide(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.divide(divideOperand,2,5).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==operand2.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算折扣率
	 * 计算公式：operand1 / (operand1 - operand2) * 100
	 * 
	 *@param datas List 取该List中的数据进行计算，并将计算后的数据存入该对象中
	 *@param operand1Idx int 第一个操作数下标位置
	 *@param operand2Idx int 第二个操作数下标位置
	 *@param dmAddIdx int 派生度量要添加到的下标位置
	 */
	private void calculateDiscountRatio(List datas,int operand1Idx,int operand2Idx,int dmAddIdx){
		List tempData = new ArrayList();
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			BigDecimal operand1 = (BigDecimal)row[operand1Idx];
			BigDecimal operand2 = (BigDecimal)row[operand2Idx];
			BigDecimal divideOperand = operand1.subtract(operand2);
			if(divideOperand.doubleValue() == 0)
				divideOperand = new BigDecimal(1);
			BigDecimal result = operand1.divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			Object[] tempRow = new Object[row.length + 1];
			for (int j = 0; j < tempRow.length; j++){
				if (j == dmAddIdx){
					tempRow[j] = result;
					if(0==divideOperand.doubleValue()) tempRow[j]="&nbsp;";
					for (int k = j; k < row.length; k++)
						tempRow[k + 1] = row[k];
					break;
				}
				tempRow[j] = row[j];
			}
			tempData.add(tempRow);
		}
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 按要求将数据集行列互换，重新组织数据
	 * （如果没有列维度，则不做任何操作）
	 *
	 *@param datas List 将行列互换后的数据存入该List对象中
	 */
	private void doXYSwap(List datas){
		if (colDimensions.size() == 0 || dimensions.size() == 0 || datas.size() == 0)
			return;
		
		int rowLength = rowDimensions.size();
		Object[] colDimValues = new Object[colDimensions.size()];
		for (int i = 0; i < colDimensions.size(); i++){
			colDimValues[i] = getDimensionValues((String)colDimensions.get(i));
			rowLength += ((Object[])colDimValues[i]).length * measures.size();
		}
		int[] rowDimIdx = new int[rowDimensions.size()];
		int[] colDimIdx = new int[colDimensions.size()];
		for (int i = 0; i < rowDimensions.size(); i++){
			String dimName = (String)rowDimensions.get(i);
			for (int j = 0; j < dimensions.size(); j++){
				if (dimName.equals((String)dimensions.get(j))){
					rowDimIdx[i] = j;
					break;
				}
			}
		}
		for (int i = 0; i < colDimensions.size(); i++){
			String dimName = (String)colDimensions.get(i);
			for (int j = 0; j < dimensions.size(); j++){
				if (dimName.equals((String)dimensions.get(j))){
					colDimIdx[i] = j;
					break;
				}
			}
		}
		
		Map dimIdxMapping = new HashMap();
		List tempData = new ArrayList();
		int index = -1;
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			String dimStr = "";
			for (int j = 0; j < rowDimIdx.length; j++){
				dimStr += (String)row[rowDimIdx[j]];
			}
			if(!dimIdxMapping.containsKey(dimStr)){
				index++;
				dimIdxMapping.put(dimStr,new Integer(index));
				Object[] tempRow = new Object[rowLength];
				for (int j = 0; j < rowDimIdx.length; j++){
					tempRow[j] = (String)row[rowDimIdx[j]];
				}
				tempData.add(tempRow);
			}
		}
		for (int i = 0; i < datas.size(); i++){
			Object[] row = (Object[])datas.get(i);
			String dimStr = "";
			for (int j = 0; j < rowDimIdx.length; j++){
				dimStr += (String)row[rowDimIdx[j]];
			}
			int idx = ((Integer)dimIdxMapping.get(dimStr)).intValue();
			Object[] tempRow = (Object[])tempData.get(idx);
			for (int j = colDimValues.length - 1; j >= 0; j--){
				String value = (String)row[colDimIdx[j]];
				Object[] values = (Object[])colDimValues[j];
				for ( int k = 0; k < values.length; k++){
					if (value.equals((String)values[k])){
						int startIdx = k * (j + 1) * measures.size() + rowDimensions.size();
						for (int m = dimensions.size(); m < row.length; m++){
							tempRow[startIdx] = row[m];
							startIdx++;
						}
					}
				}
			}
		}
		
		int[] meaScale = new int[measures.size()];
		Object[] oldRow = (Object[])datas.get(0);
		for (int i = dimensions.size(); i < oldRow.length; i++){
			meaScale[i - dimensions.size()] = ((BigDecimal)oldRow[i]).scale();
		}
		for (int i = 0; i < tempData.size(); i++){
			Object[] tempRow = (Object[])tempData.get(i);
			for (int j = rowDimensions.size(); j < tempRow.length; j++){
				if (tempRow[j] == null){
					int scale = meaScale[(j - rowDimensions.size()) % meaScale.length];
					tempRow[j] = new BigDecimal(0).setScale(scale);
				}
			}
		}
		
		datas.clear();
		datas.addAll(tempData);
	}
	
	/**
	 * 计算报表小计
	 *
	 *@param datas List 将小计后的数据存入该List对象中
	 */
	private void doSubtotal(List datas){
		if (datas.size() == 0 || subtotals.size() == 0)
			return;
		if (dimensions.size() == 0 || measures.size() == 0)
			return;
		
		int xTotalCnt = 0;
		int yTotalCnt = 0;
		//没有列维度时的汇总方式
		if (colDimensions.size() == 0){
			for (int i = 0; i < subtotals.size(); i++){
				String[] subtotal = (String[])subtotals.get(i);
				if (subtotal[0].equals(TOP) || subtotal[0].equals(BOTTOM)){
					xTotalCnt++;
					if (xTotalCnt > 1)
						continue;
					calculateRowTotal(datas,subtotal[0],dimensions.size());
				}
				else{
					yTotalCnt++; 
					if (yTotalCnt > 1)
						continue;
					List tempData = new ArrayList();
					for (int j = 0; j < datas.size(); j++){
						Object[] row = (Object[])datas.get(j);
						BigDecimal total = new BigDecimal(0);
						for (int k = dimensions.size(); k < row.length; k++){
							total = total.add((row[k] instanceof String)?new BigDecimal("0.0"):(BigDecimal)row[k]);
						}
						Object[] tempRow = new Object[row.length + 1];
						for (int k = 0; k < dimensions.size(); k++)
							tempRow[k] = row[k];
						if (subtotal[0].equals(RIGHT)){
							for (int k = dimensions.size(); k < row.length; k++)
								tempRow[k] = row[k];
							if (subtotal[1].equals(SUM))
								tempRow[row.length] = total;
							if (subtotal[1].equals(AVG))
								tempRow[row.length] = total.divide(new BigDecimal(measures.size()),5);
						}
						else{
							if (subtotal[1].equals(SUM))
								tempRow[dimensions.size()] = total;
							if (subtotal[1].equals(AVG))
								tempRow[dimensions.size()] = total.divide(new BigDecimal(measures.size()),5);
							for (int k = dimensions.size(); k < row.length; k++)
								tempRow[k + 1] = row[k];
						}
						tempData.add(tempRow);
					}
					datas.clear();
					datas.addAll(tempData);
				}
			}
		}
		//有列维度时的汇总方式
		//（有列维度时数据集经过了行列互换和数据重组，汇总方式有所不同）
		else{
			int rightTotalCnt = 0;
			int leftTotalCnt = 0;
			for (int i = 0; i < subtotals.size(); i++){
				String[] subtotal = (String[])subtotals.get(i);
				if (subtotal[0].equals(TOP) || subtotal[0].equals(BOTTOM)){
					xTotalCnt++;
					if (xTotalCnt > 1)
						continue;
					calculateRowTotal(datas,subtotal[0],rowDimensions.size());
				}
				else{
					int meaStartIdx = rowDimensions.size();
					List tempData = new ArrayList();
					for (int j = 0; j < datas.size(); j++){
						Object[] row = (Object[])datas.get(j);
						BigDecimal total = new BigDecimal(0);
						for (int k = meaStartIdx; k < row.length; k++){
							if (k < meaStartIdx + leftTotalCnt)
								continue;
							if (k >= row.length - rightTotalCnt)
								continue;
							String meaName = (String)measures.get((k - meaStartIdx - leftTotalCnt) % measures.size());
							if (subtotal[2].equals(meaName))
								total = total.add((row[k] instanceof String)?new BigDecimal("0.0"):(BigDecimal)row[k]);
						}
						Object[] tempRow = new Object[row.length + 1];
						for (int k = 0; k < meaStartIdx; k++)
							tempRow[k] = row[k];
						if (subtotal[0].equals(RIGHT)){
							for (int k = meaStartIdx; k < row.length; k++)
								tempRow[k] = row[k];
							if (subtotal[1].equals(SUM))
								tempRow[row.length] = total;
							else if (subtotal[1].equals(AVG))
								tempRow[row.length] = total.divide(new BigDecimal((row.length - meaStartIdx) / measures.size()),5);
							else ;
						}
						else{
							if (subtotal[1].equals(SUM))
								tempRow[meaStartIdx] = total;
							else if (subtotal[1].equals(AVG))
								tempRow[meaStartIdx] = total.divide(new BigDecimal((row.length - meaStartIdx) / measures.size()),5);
							else ;
							for (int k = meaStartIdx; k < row.length; k++)
								tempRow[k + 1] = row[k];
						}
						tempData.add(tempRow);
					}
					datas.clear();
					datas.addAll(tempData);
					
					if (subtotal[0].equals(RIGHT))
						rightTotalCnt++;
					else
						leftTotalCnt++;
				}
			}
		}
	}
	
	/**
	 * 计算行小计
	 *
	 *@param datas List 取该List中的数据进行汇总，并将汇总后的数据存入该对象中
	 *@param position String 小计的位置（在这里只能是TOP和BOTTOM）
	 *@param meaStartIdx int 度量在每一行中开始位置的下标（没有列维度dimensions.size()，有列维度rowDimensions.size()）
	 */
	private void calculateRowTotal(List datas,String position,int meaStartIdx){
		Object[] totals = null;
		for (int j = 0; j < datas.size(); j++){
			Object[] row = (Object[])datas.get(j);
			if (j==0){
				totals = new Object[row.length];
				for (int k = 0; k < meaStartIdx; k++)
					totals[k] = "";
				for (int k = meaStartIdx; k < row.length; k++)
					totals[k] = new BigDecimal(0);
			}
			for (int k = meaStartIdx; k < row.length; k++){ 
				
				totals[k] = ((BigDecimal)totals[k]).add((row[k] instanceof String)?new BigDecimal("0.0"):(BigDecimal)row[k]);
			}
		}
		//默认汇总全部是按求和计算，现在重新计算那些不能按求和计算的度量
		for (int j = 0; j < subtotals.size(); j++){
			String[] tempTotal = (String[])subtotals.get(j);
			if (tempTotal[1].equals(AVG) && (tempTotal[0].equals(TOP) || tempTotal[0].equals(BOTTOM))){
				for (int k = meaStartIdx; k < totals.length; k++){
					String meaName = (String)measures.get((k - meaStartIdx) % measures.size());
					if (tempTotal[2].equals(meaName)){
						totals[k] = ((BigDecimal)totals[k]).divide(new BigDecimal(datas.size()),5);
					}
				}
			}
		}
		//派生度量的汇总
		if (deriveMeasures.size() > 0){
			for (int j = meaStartIdx; j < totals.length; j++){
				String meaName = (String)measures.get((j - meaStartIdx) % measures.size());
				for (int k = 0; k < deriveMeasures.size(); k++){
					String[] dMeasure = (String[])deriveMeasures.get(k);
					if (meaName.equals(dMeasure[0])){
						calculateRowTotalDM(totals,dMeasure,j,meaStartIdx);
					}
				}
			}
		}
		if(position.equals(TOP))
			datas.add(0,totals);
		else
			datas.add(totals);
	}
	
	/**
	 * 计算行小计（派生度量）
	 *
	 *@param totalRow Object[] 汇总行，取该汇总行中的数据计算派生度量的小计值，并将计算结果替换相应位置的值
	 *@param dMeasure String[] 派生度量定义
	 *@param dMeasureIdx int 派生度量在汇总行中的下标位置
	 *@param meaStartIdx int 度量在每一行中开始位置的下标
	 */
	private void calculateRowTotalDM(Object[] totalRow,String[] dMeasure,int dMeasureIdx,int meaStartIdx){
		int operand1Idx = -1;
		int operand2Idx = -1;
		for (int j = 2; j < dMeasure.length; j++){
			boolean exist = false;
			for (int k = 0; k < measures.size(); k++){
				if (dMeasure[j].equals((String)measures.get(k))){
					exist = true;
					if (j == 2)
						operand1Idx = meaStartIdx + k;
					if (j == 3)
						operand2Idx = meaStartIdx + k;
					break;
				}
			}
			if (!exist)
				return;
		}
		int cnt = (dMeasureIdx - meaStartIdx) / measures.size();
		if (cnt > 0){
			operand1Idx = operand1Idx + measures.size() * cnt;
			operand2Idx = operand2Idx + measures.size() * cnt;
		}
		
		if (dMeasure[1].equals(Report.CYCLE_RATIO)){
			BigDecimal operand1 = (BigDecimal)totalRow[operand1Idx];
			BigDecimal operand2 = (BigDecimal)totalRow[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.subtract(operand2).divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			//if(0==operand2.doubleValue()) result="";
			totalRow[dMeasureIdx] = result;
		}
		else if (dMeasure[1].equals(Report.COMPOSING_RATIO)){
			totalRow[dMeasureIdx] = new BigDecimal(100.00).setScale(2);
		}
		else if (dMeasure[1].equals(Report.RANKING)){
			totalRow[dMeasureIdx] = new BigDecimal(0);
		}
		else if (dMeasure[1].equals(Report.RATIO)){
			BigDecimal operand1 = (BigDecimal)totalRow[operand1Idx];
			BigDecimal operand2 = (BigDecimal)totalRow[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			//if(0==operand2.doubleValue()) result="";
			totalRow[dMeasureIdx] = result;
		}
		else if (dMeasure[1].equals(Report.BRING_INCREASE_RATIO)){
			;//保持求和不变
		}
		else if (dMeasure[1].equals(Report.INVERSE_RATIO)){
			BigDecimal operand1 = (BigDecimal)totalRow[operand1Idx];
			BigDecimal operand2 = (BigDecimal)totalRow[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = (new BigDecimal(1)).subtract(operand1.divide(divideOperand,4,5)).multiply(new BigDecimal(100)).setScale(2);
			totalRow[dMeasureIdx] = result;
		}
		else if (dMeasure[1].equals(Report.DIVIDE)){
			BigDecimal operand1 = (BigDecimal)totalRow[operand1Idx];
			BigDecimal operand2 = (BigDecimal)totalRow[operand2Idx];
			BigDecimal divideOperand = new BigDecimal(1);
			if(operand2.doubleValue() != 0)
				divideOperand = operand2;
			BigDecimal result = operand1.divide(divideOperand,2,5).setScale(2);
			totalRow[dMeasureIdx] = result;
		}
		else if (dMeasure[1].equals(Report.DISCOUNT_RATIO)){
			BigDecimal operand1 = (BigDecimal)totalRow[operand1Idx];
			BigDecimal operand2 = (BigDecimal)totalRow[operand2Idx];
			BigDecimal divideOperand = operand1.subtract(operand2);
			if(divideOperand.doubleValue() == 0)
				divideOperand = new BigDecimal(1);
			BigDecimal result = operand1.divide(divideOperand,4,5).multiply(new BigDecimal(100)).setScale(2);
			totalRow[dMeasureIdx] = result;
		}
		else ;
	}
	
	/**
	 * 添加、移除报表筛选
	 *
	 *@param fName String 筛选名称，一般是一个具体的维度名称
	 *@param fValue String[] 筛选值列表
	 */
	public void addFilter(String fName,String[] fValue){
		if(reportData.getColumnIndex(fName) != -1)
			filters.put(fName,fValue);
	}
	public void removeAllFilter(){
		filters.clear();
	}
	
	/**
	 * 添加、移除报表维度
	 * （添加的维度默认作为行维度）
	 *
	 *@param dName String[] 维度名称列表
	 */
	public void addDimension(String[] dName){
		for (int i = 0; i< dName.length; i++){
			int colIdx = reportData.getColumnIndex(dName[i]);
			if(colIdx != -1){
				String colType = reportData.getColumnType(colIdx + 1);
				if(colType.indexOf("CHAR") != -1){
					dimensions.add(dName[i]);
					rowDimensions.add(dName[i]);
				}
			}
		}
	}
	public void removeAllDimension(){
		dimensions.clear();
		rowDimensions.clear();
		colDimensions.clear();
	}
	
	/**
	 * 添加报表维度
	 *
	 *@param position String 维度的位置（行维度还是列维度）
	 *@param dName String[] 维度名称列表
	 */
	public void addDimension(String position,String[] dName){
		for (int i = 0; i< dName.length; i++){
			int colIdx = reportData.getColumnIndex(dName[i]);
			if(colIdx != -1){
				String colType = reportData.getColumnType(colIdx + 1);
				if(colType.indexOf("CHAR") != -1){
					dimensions.add(dName[i]);
					if (position.equalsIgnoreCase(COLUMN_DIMENSION))
						colDimensions.add(dName[i]);
					else
						rowDimensions.add(dName[i]);
				}
			}
		}
	}
	
	/**
	 * 添加、移除报表度量
	 *
	 *@param mName String[] 度量名称列表
	 */
	public void addMeasure(String[] mName){
		for (int i = 0; i < mName.length; i++){
			int colIdx = reportData.getColumnIndex(mName[i]);
			if(colIdx != -1){
				String colType = reportData.getColumnType(colIdx + 1);
				if(colType.indexOf("CHAR") == -1)
					measures.add(mName[i]);
			}
		}
	}
	public void removeAllMeasure(){
		measures.clear();
	}
	
	/**
	 * 添加、移除报表隐藏度量
	 *
	 *@param mName String[] 隐藏度量名称列表
	 */
	public void addHiddenMeasure(String[] mName){
		for (int i = 0; i < mName.length; i++){
			int colIdx = reportData.getColumnIndex(mName[i]);
			if(colIdx != -1){
				String colType = reportData.getColumnType(colIdx + 1);
				if(colType.indexOf("CHAR") == -1)
					hiddenMeasures.add(mName[i]);
			}
		}
	}
	public void removeAllHiddenMeasure(){
		hiddenMeasures.clear();
	}
	
	/**
	 * 添加、移除报表自动计算的派生度量
	 *
	 *@param dmName String 派生度量名称
	 *@param dmType String 派生度量类型
	 *@param dmParams String[] 计算派生度量的参数，即报表中存在的度量名称
	 */
	public void addDeriveMeasure(String dmName,String dmType,String[] dmParams){
		if (!(dmType.equals(CYCLE_RATIO) || dmType.equals(COMPOSING_RATIO) || dmType.equals(RANKING)
				|| dmType.equals(RATIO) || dmType.equals(BRING_INCREASE_RATIO)
				|| dmType.equals(INVERSE_RATIO) || dmType.equals(DIVIDE) || dmType.equals(DISCOUNT_RATIO) ))
			return;
		if (dmType.equals(CYCLE_RATIO) && dmParams.length != 2)
			return;
		if (dmType.equals(COMPOSING_RATIO) && dmParams.length != 1)
			return;
		if (dmType.equals(RANKING) && dmParams.length != 1)
			return;
		if (dmType.equals(RATIO) && dmParams.length != 2)
			return;
		if (dmType.equals(BRING_INCREASE_RATIO) && dmParams.length != 2)
			return;
		if (dmType.equals(INVERSE_RATIO) && dmParams.length != 2)
			return;
		if (dmType.equals(DIVIDE) && dmParams.length != 2)
			return;
		if (dmType.equals(DISCOUNT_RATIO) && dmParams.length != 2)
			return;
		
		String[] dMeasure = new String[dmParams.length + 2];
		dMeasure[0] = dmName;
		dMeasure[1] = dmType;
		for (int i = 0; i < dmParams.length; i++)
			dMeasure[i + 2] = dmParams[i];
		deriveMeasures.add(dMeasure);
	}
	public void removeAllDeriveMeasure(){
		deriveMeasures.clear();
	}
	
	/**
	 * 添加、移除报表小计
	 *
	 *@param position String 小计的位置
	 *@param calcType String 小计的计算方法
	 *@param measureNm String 参与小计的度量名称
	 */
	public void addSubtotal(String position){
		for (int i = 0; i < measures.size(); i++){
			addSubtotal(position,SUM,(String)measures.get(i));
		}
	}
	public void addSubtotal(String position,String calcType){
		for (int i = 0; i < measures.size(); i++){
			addSubtotal(position,calcType,(String)measures.get(i));
		}
	}
	public void addSubtotal(String position,String calcType,String measureNm){
		if (!(calcType.equalsIgnoreCase(SUM) || calcType.equalsIgnoreCase(AVG)))
			return;
		if (!(position.equalsIgnoreCase(TOP) || position.equalsIgnoreCase(BOTTOM) || position.equalsIgnoreCase(LEFT) || position.equalsIgnoreCase(RIGHT)))
			return;
		int colIdx = reportData.getColumnIndex(measureNm);
		if(colIdx != -1)
			subtotals.add(new String[]{position,calcType,measureNm});
	}
	public void removeAllSubtotal(){
		subtotals.clear();
	}
	
	/**
	 * 得到某一维度的所有取值（排除重复值，各取值按升序排列）
	 *
	 *@param dName String 维度名称
	 *@return Object[] 返回指定维度的取值集合
	 */
	public Object[] getDimensionValues(String dName){
		int colIdx = reportData.getColumnIndex(dName);
		if(colIdx != -1){
			if (dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_CITY)){
				if (!cityScope.equals(InitParam.PROVINCECODE_IN_CITYCODE))
					return new Object[]{cityScope};
				else
					return reportData.getColumnValues(colIdx);
			}
			else if (dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_COUNTRY)){
				if (!countryScope.equals(InitParam.CITYCODE_IN_COUNTRYCODE))
					return new Object[]{countryScope};
				else if (!cityScope.equals(InitParam.PROVINCECODE_IN_CITYCODE)){
					int restrictColIdx = reportData.getColumnIndex(InitParam.DIMENSION_ALIAS_INSQL_CITY);
					if (restrictColIdx != -1)
						return reportData.getColumnValues(colIdx,restrictColIdx,cityScope);
					else
						return reportData.getColumnValues(colIdx);
				}
				else
					return reportData.getColumnValues(colIdx);
			}
			else
				return reportData.getColumnValues(colIdx);
		}
		else
			return new Object[]{};
	}
	
	/**
	 * 得到某一维度的所有取值，带有限制条件（排除重复值，各取值按升序排列）
	 *
	 *@param dName String 维度名称
	 *@param restrictDName String 要作为限制条件的维度名称
	 *@param restrictValue String 限制条件的值
	 *@return Object[] 返回指定维度的取值集合
	 */
	public Object[] getDimensionValues(String dName,String restrictDName,String restrictValue){
		int colIdx = reportData.getColumnIndex(dName);
		int restrictColIdx = reportData.getColumnIndex(restrictDName);
		if (colIdx == -1)
			return new Object[]{};
		if (restrictColIdx != -1)
			return reportData.getColumnValues(colIdx,restrictColIdx,restrictValue);
		else
			return reportData.getColumnValues(colIdx);
	}
	
	/**
	 * 得到某一维度的最大值
	 *
	 *@param dName String 维度名称
	 *@return Object 返回指定维度的最大值
	 */
	public Object getDimensionMaxValue(String dName){
		int colIdx = reportData.getColumnIndex(dName);
		if(colIdx != -1){
			if (dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_DATE) || dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_MONTH)){
				int restrictColIdx = reportData.getColumnIndex(InitParam.DIMENSION_ALIAS_INSQL_CITY);
				if (!cityScope.equals(InitParam.PROVINCECODE_IN_CITYCODE) && restrictColIdx != -1)
					return reportData.getColumnMaxValue(colIdx,restrictColIdx,cityScope);
				else
					return reportData.getColumnMaxValue(colIdx);
			}
			else
				return reportData.getColumnMaxValue(colIdx);
		}
		else
			return "";
	}
	
	/**
	 * 得到某一维度的最小值
	 *
	 *@param dName String 维度名称
	 *@return Object 返回指定维度的最小值
	 */
	public Object getDimensionMinValue(String dName){
		int colIdx = reportData.getColumnIndex(dName);
		if(colIdx != -1){
			if (dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_DATE) || dName.equalsIgnoreCase(InitParam.DIMENSION_ALIAS_INSQL_MONTH)){
				int restrictColIdx = reportData.getColumnIndex(InitParam.DIMENSION_ALIAS_INSQL_CITY);
				if (!cityScope.equals(InitParam.PROVINCECODE_IN_CITYCODE) && restrictColIdx != -1)
					return reportData.getColumnMinValue(colIdx,restrictColIdx,cityScope);
				else
					return reportData.getColumnMinValue(colIdx);
			}
			else
				return reportData.getColumnMinValue(colIdx);
		}
		else
			return "";
	}
	
	/**
	 * 得到某一列的标签
	 *
	 *@param cName String 列名称
	 *@return String 返回指定列的标签值
	 */
	public String getColumnTitle(String cName){
		int colIdx = reportData.getColumnIndex(cName);
		if (colIdx != -1)
			return reportData.getColumnLabel(colIdx + 1);
		else
			return "";
	}
	
	/**
	 * 根据数据的ID维度值找到对应的Name维度值
	 * （这种方法在客户端频繁调用时性能可能会存在问题，有待想办法用别的方法来实现这个功能）
	 *
	 *@param idDimName String ID维度名称
	 *@param nameDimName String Name维度名称
	 *@param idValue String ID值
	 *@return Object 返回ID对应的Name值
	 */
	public Object getNameValueByID(String idDimName,String nameDimName,String idValue){
		int idColIdx = reportData.getColumnIndex(idDimName);
		int nameColIdx = reportData.getColumnIndex(nameDimName);
		if(idColIdx == -1 || nameColIdx == -1)
			return "";
		else
			return reportData.getNameValueByID(idColIdx,nameColIdx,idValue);
	}
	
	/**
	 * 根据当前用户的属性，返回默认显示的地域维度别名
	 *
	 *@return String 返回ID对应的Name值
	 */
	public String getDefaultAreaIdAlias(){
		return defaultAreaIdAlias;
	}
	public String getDefaultAreaNameAlias(){
		return defaultAreaNameAlias;
	}
	
	/**
	 * 得到某一维度名称对应的ID别名或NAME别名
	 *
	 *@param dName String 维度名称
	 *@return String 返回与指定维度名称相匹配的别名
	 */
	/**public String matchIdOrNameAlias(String dName){
		String matchName = "";
		if(dName.substring(dName.lastIndexOf("_")).equalsIgnoreCase("_ID")){
			matchName = dName.substring(0,dName.lastIndexOf("_")) + "_NAME";
			if (reportData.getColumnIndex(matchName) != -1)
				return matchName;
			else
				return dName;
		}
		else if(dName.substring(dName.lastIndexOf("_")).equalsIgnoreCase("_NAME")){
			matchName = dName.substring(0,dName.lastIndexOf("_")) + "_ID";
			if (reportData.getColumnIndex(matchName) != -1)
				return matchName;
			else
				return dName;
		}
		else
			return dName;
	}*/
	
	/**
	 * 检查是否为隐藏度量
	 *
	 *@param mName String 度量名称
	 *@return boolean 返回是否为隐藏度量
	 */
	private boolean isHiddenMeasure(String mName){
		if (hiddenMeasures.size() == 0)
			return false;
		for (int i = 0; i < hiddenMeasures.size(); i++){
			if (mName.equalsIgnoreCase((String)hiddenMeasures.get(i)))
				return true;
		}
		return false;
	}
}